package com.powernode.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.powernode.document.ProductDoc;
import com.powernode.dto.PageResult;
import com.powernode.param.ProductSearchParam;
import com.powernode.repository.ProductDocRepository;
import com.powernode.service.ProductDocService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

@Service
public class ProductDocServiceImpl implements ProductDocService {
    @Autowired
    private ProductDocRepository repository;
    @Autowired
    private ElasticsearchRestTemplate template;

    @Override
    public PageResult<ProductDoc> search(ProductSearchParam param) {
        // 如果搜索条件中关键字为空，返回一个空对象
        if (StrUtil.isBlankOrUndefined(param.getKeyword())) {
            return new PageResult<>();
        }
        //创建一个bool查询创建器
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //添加一个match单字段搜索，对keyword进行搜索
        boolQueryBuilder.must(QueryBuilders.matchQuery("keyword", param.getKeyword()));

        //获取价格区间
        BigDecimal highPrice = param.getHighPrice();
        BigDecimal lowPrice = param.getLowPrice();
        //添加一个精准查询之range范围查询，对价格区间进行搜索
        if (ObjectUtil.isAllNotEmpty(lowPrice, highPrice)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(highPrice).gte(lowPrice));
        }
        //构造高亮查询
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //设置高亮字段
        highlightBuilder
                //设置所有字段高亮
                //.field("*")
                //.field("keyword")
                .field("title")
                .field("intro")
                .field("categoryNameLevel1")
                .field("categoryNameLevel2")
                .field("categoryNameLevel3")
                .preTags("<font color='pink'><b>")
                .postTags("</b></font>")

                .requireFieldMatch(false);

        //构造查询对象
        Query query = new NativeSearchQueryBuilder()
                                            .withQuery(boolQueryBuilder)
                                            .withHighlightBuilder(highlightBuilder)
                                            .build();

        //获取排序字段
        String orderBy = param.getOrderBy();
        //获取排序方向
        String direction = param.getDirection();
        //创建一个排序方向的对象
        Sort.Direction sortDirection = null;
        //如果没有设置默认降序（因为销量一般都是降序）
        if ("desc".equalsIgnoreCase(direction) || StrUtil.isBlank(direction)) {
            sortDirection = Sort.Direction.DESC;
        }
        if ("asc".equalsIgnoreCase(direction)) {
            sortDirection = Sort.Direction.ASC;
        }
        //根据排序字段添加排序并设置排序方向
        if (StrUtil.isNotBlank(orderBy)) {
            query.addSort(Sort.by(sortDirection, orderBy));
        }
        //对查询结果进行分页,spring-data自带的PageRequest的静态方法传入当前页码和每页条数
        Integer current = param.getCurrent();
        current = ObjectUtil.isNull(current) ? 0 : current-1;
        Integer size = param.getSize();
        size = ObjectUtil.isNull(size) ? 20 : size;
        //设置分页信息--每页条数和当前页码
        query.setPageable(PageRequest.of(current, size));
        //查询
        SearchHits<ProductDoc> searchHits = template.search(query, ProductDoc.class);
        //构造分页结果的记录
        List<ProductDoc> records = new ArrayList<>();
        searchHits.forEach(item -> {
            //获取keyword字段
//            List<String> keywordList = item.getHighlightField("keyword");
//            if (CollectionUtil.isNotEmpty(keywordList)){
//                //设置keyword高亮
//                item.getContent().setKeyword(keywordList.get(0));
//            }

            //获取title字段
            List<String> titleList = item.getHighlightField("title");
            if (CollectionUtil.isNotEmpty(titleList)){
                //设置title高亮
                item.getContent().setTitle(titleList.get(0));
            }

            //获取intro字段
            List<String> introList = item.getHighlightField("intro");
            if (CollectionUtil.isNotEmpty(introList)){
                //设置intro高亮
                item.getContent().setIntro(introList.get(0));
            }
            //获取categoryNameLevel1字段
            List<String> categoryNameLevel1List = item.getHighlightField("categoryNameLevel1");
            if (CollectionUtil.isNotEmpty(categoryNameLevel1List)){
                //设置categoryNameLevel1高亮
                item.getContent().setCategoryNameLevel1(categoryNameLevel1List.get(0));
            }
            //获取categoryNameLevel2字段
            List<String> categoryNameLevel2List = item.getHighlightField("categoryNameLevel2");
            if (CollectionUtil.isNotEmpty(categoryNameLevel2List)){
                //设置categoryNameLevel2高亮
                item.getContent().setCategoryNameLevel2(categoryNameLevel2List.get(0));
            }
            //获取categoryNameLevel3字段
            List<String> categoryNameLevel3List = item.getHighlightField("categoryNameLevel3");
            if (CollectionUtil.isNotEmpty(categoryNameLevel3List)){
                //设置categoryNameLevel3高亮
                item.getContent().setCategoryNameLevel3(categoryNameLevel3List.get(0));
            }

            //System.out.println(item.getContent().getKeyword());

            records.add(item.getContent());
        });

        return new PageResult<>(searchHits.getTotalHits(), records);
    }

    @Override
    public void saveOrUpdate(ProductDoc productDoc) {
        repository.save(productDoc);
    }

    @Override
    public void deleteById(Long id) {
        repository.deleteById(id);
    }
}
